package com.yunke.common.log;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 业务日志切面
 * 
 * @author yunke
 * @since 1.0.0
 */
@Slf4j
@Aspect
@Component
public class BusinessLogAspect {

    @Autowired
    private ObjectMapper objectMapper;

    private static final String BUSINESS_LOGGER_NAME = "com.yunke.business";

    /**
     * 环绕通知：处理@BusinessLog注解
     */
    @Around("@annotation(businessLog)")
    public Object around(ProceedingJoinPoint joinPoint, BusinessLog businessLog) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = method.getName();
        
        // 获取请求信息
        String clientIp = "system";
        String userAgent = "";
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            clientIp = getClientIpAddress(request);
            userAgent = request.getHeader("User-Agent");
        }
        
        // 构建日志信息
        StringBuilder logBuilder = new StringBuilder();
        logBuilder.append("\n========== 业务操作日志 ==========");
        logBuilder.append("\n操作时间: ").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        logBuilder.append("\n业务模块: ").append(businessLog.module());
        logBuilder.append("\n操作类型: ").append(businessLog.type().getDescription());
        logBuilder.append("\n操作描述: ").append(businessLog.operation());
        logBuilder.append("\n执行方法: ").append(className).append(".").append(methodName);
        logBuilder.append("\n客户端IP: ").append(clientIp);
        
        // 记录请求参数
        if (businessLog.logParams()) {
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0) {
                logBuilder.append("\n请求参数: ").append(toJsonString(args));
            }
        }
        
        Object result = null;
        Exception exception = null;
        
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            
            // 记录返回结果
            if (businessLog.logResult() && result != null) {
                String resultStr = toJsonString(result);
                // 如果结果过长，截断显示
                if (resultStr.length() > 500) {
                    resultStr = resultStr.substring(0, 500) + "...";
                }
                logBuilder.append("\n返回结果: ").append(resultStr);
            }
            
        } catch (Exception e) {
            exception = e;
            logBuilder.append("\n执行异常: ").append(e.getMessage());
            throw e;
        } finally {
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            logBuilder.append("\n执行时间: ").append(executionTime).append("ms");
            logBuilder.append("\n执行状态: ").append(exception == null ? "成功" : "失败");
            logBuilder.append("\n================================");
            
            // 使用业务日志Logger输出
            org.slf4j.Logger businessLogger = org.slf4j.LoggerFactory.getLogger(BUSINESS_LOGGER_NAME);
            if (exception == null) {
                businessLogger.info(logBuilder.toString());
            } else {
                businessLogger.error(logBuilder.toString());
            }
        }
        
        return result;
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        String proxyClientIp = request.getHeader("Proxy-Client-IP");
        if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
            return proxyClientIp;
        }
        
        String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
        if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
            return wlProxyClientIp;
        }
        
        return request.getRemoteAddr();
    }

    /**
     * 对象转JSON字符串
     */
    private String toJsonString(Object object) {
        if (object == null) {
            return "null";
        }
        
        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            log.warn("对象转JSON失败: {}", e.getMessage());
            return object.toString();
        }
    }
} 